# Copyright (c) 2009 Peter Corbett
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

import colours
import utils

class Renderer:
    def __init__(self, pgc, data):
        self.pgc = pgc
        self.data = data

    def render(self, state):
        self.clear_panel()
        self.render_level(state.current_level, state, state.lostab, state.cheat_omniscent)
        self.render_panel(state)
        #if state.resting:
        #    x = 1 / 0
        #self.pgc.refresh()

    def render_level(self, level, state, los, omni, cursor=None):
        pc = state.pc
        blind = "blind" in pc.statuses
        for x in range(80):
            for y in range(20):
                if omni or level.known[x][y]:
                    ft = level.floortiles[x][y]
                    ftd = self.data.floortiles[ft]
                    self.pgc.addch(x, y+1, ftd.ch, ftd.fg if los[x][y] and not blind else ftd.fgd, ftd.bg if los[x][y] and not blind else ftd.bgd)
                    if level.items[x][y]:
                        itm = level.items[x][y][-1]
                        itmtype = self.data.itemtypes[itm.type]
                        self.pgc.addch(x, y+1, itmtype.ch, itmtype.fg, itmtype.bg)
                else:
                    self.pgc.addch(x, y+1, " ", 7, 0)
        self.render_mob(pc)
        for mob in level.mobs:
            if omni or pc.can_see(mob, state, self.data):
                self.render_mob(mob)
        if cursor != None:
            self.pgc.setbg(cursor[0], cursor[1]+1, colours.DARKGREEN)

    def render_mob(self, mob):
        mobtype = self.data.mobtypes[mob.type]
        self.pgc.addch(mob.x, mob.y+1, mobtype.ch, mobtype.fg, mobtype.bg)

    def render_message(self, message):
        self.pgc.addstr(0, 0, " " * 80, 7, 0)
        if message is not None:
            self.pgc.addstr(0, 0, message, 7, 0)

    def render_inv(self, inv, slots=None, test=None):
        for x in range(80):
            for y in range(20):
                self.pgc.addch(x, y+1, " ", 7, 0)

        for i in range(len(inv)):
            ch = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"[i]
            itype = self.data.itemtypes[inv[i].type]
            if test is not None and not test(inv[i], itype):
                continue
            iname = itype.name
            icolor = itype.fg
            slot = inv[i].slot
            self.pgc.addstr((i/18) * 40, (i % 18)+2, "%s) %s%s" % (ch, inv[i].desc(self.data, ""),
                                                  " (%s)" % self.data.slottypes[self.data.slotdict[slot]].desc if slot else ""),
                            icolor, 0)

    def render_spells(self, spells):
        for x in range(80):
            for y in range(20):
                self.pgc.addch(x, y+1, " ", 7, 0)

        for i in range(len(spells)):
            ch = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"[i]
            stype = self.data.spelltypes[spells[i]]
            sname = stype.name
            scolor = stype.fg
            mstr = str(stype.mana)
            s = "%s) %s" % (ch, sname)
            s = "%s%s%s" % (s, " " * (39 - len(s) - len(mstr)), mstr)
            self.pgc.addstr((i/18) * 40, (i % 18)+2, s, scolor, 0)


    def render_character(self, pc, data):
        for x in range(80):
            for y in range(20):
                self.pgc.addch(x, y+1, " ", 7, 0)

        self.pgc.addstr(0, 2,   "Base Stats", colours.WHITE, colours.BLACK)        
        self.pgc.addstr(0, 3,   "Strength      % 4d" % pc.str, colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(0, 4,   "Agility       % 4d" % pc.agi, colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(0, 5,   "Intelligence  % 4d" % pc.int, colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(0, 6,   "Willpower     % 4d" % pc.wp,  colours.LIGHTGREY, colours.BLACK)

        self.pgc.addstr(0, 8,   "Movement", colours.WHITE, colours.BLACK)        
        self.pgc.addstr(0, 9,   "Armour        % 4d" % pc.sdict["armour"], colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(0, 10,  "Encumberance  % 4d" % pc.sdict["enc"], colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(0, 11,  "Speed         %+4d" % pc.sdict["speed"],  colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(0, 12,  "Initiative    % 4d" % pc.sdict["init"],  colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(0, 13,  "Awareness     % 4d" % pc.sdict["spot"],  colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(0, 14,  "Stealth       % 4d" % pc.sdict["sneak"],  colours.LIGHTGREY, colours.BLACK)

        self.pgc.addstr(20, 2,  "Hand-To-Hand", colours.WHITE, colours.BLACK)
        self.pgc.addstr(20, 3,  "To Hit        % 4d" % pc.sdict["hthhit"], colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(20, 4,  "Power         % 4d" % pc.sdict["hthpow"], colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(20, 5,  "Speed         %+4d" % pc.sdict["hthspeed"], colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(20, 6,  "Defense       % 4d" % pc.sdict["hthdef"], colours.LIGHTGREY, colours.BLACK)

        self.pgc.addstr(20, 8,  "Ranged", colours.WHITE, colours.BLACK)
        self.pgc.addstr(20, 9,  "To Hit        % 4d" % pc.sdict["mishit"], colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(20, 10, "Power         % 4d" % pc.sdict["mispow"], colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(20, 11, "Speed         %+4d" % pc.sdict["misspeed"], colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(20, 12, "Defense       % 4d" % pc.sdict["misdef"], colours.LIGHTGREY, colours.BLACK)

        self.pgc.addstr(40, 2,  "Magic/Abilities", colours.WHITE, colours.BLACK)
        self.pgc.addstr(40, 3,  "Penetration   % 4d" % pc.sdict["maghit"], colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(40, 4,  "Power         % 4d" % pc.sdict["magpow"], colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(40, 5,  "Speed         %+4d" % pc.sdict["magspeed"], colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(40, 6,  "Resistance    % 4d" % pc.sdict["magdef"], colours.LIGHTGREY, colours.BLACK)


        


    def refresh(self):
        self.pgc.refresh()

    def clear(self):
        for x in range(80):
            for y in range(25):
                self.pgc.addch(x, y, " ", 7, 0)

    def clear_panel(self):
        for x in range(80):
            for y in range(21, 25):
                self.pgc.addch(x, y, " ", 7, 0)

    def render_panel(self, state):
        self.clear_panel()
        self.pgc.addstr(0, 21, "Level ", colours.WHITE, colours.BLACK)
        self.pgc.addstr(6, 21, "%s" % state.pc.level, colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(9, 21, "HP ", colours.WHITE, colours.BLACK)
        self.pgc.addstr(12, 21, "%s/%s" % (state.pc.hp, state.pc.maxhp), utils.fract_colour(state.pc.hp, state.pc.maxhp), colours.BLACK)
        self.pgc.addstr(22, 21, "MP ", colours.WHITE, colours.BLACK)
        self.pgc.addstr(25, 21, "%s/%s" % (state.pc.mp, state.pc.maxmp), utils.fract_colour(state.pc.mp, state.pc.maxmp), colours.BLACK)
        self.pgc.addstr(35, 21, "AU ", colours.WHITE, colours.BLACK)
        self.pgc.addstr(38, 21, "%s" % (state.pc.au), colours.YELLOW, colours.BLACK)
        self.pgc.addstr(45, 21, "XP ", colours.WHITE, colours.BLACK)
        self.pgc.addstr(48, 21, "%s" % (state.xp), colours.LIGHTGREY, colours.BLACK)
        self.pgc.addstr(71, 21, "Depth ", colours.WHITE, colours.BLACK)
        self.pgc.addstr(77, 21, "%s" % (state.level + 1), colours.LIGHTGREY, colours.BLACK)
        x = 0
        for s in state.pc.statuses:
            status = state.pc.statuses[s]
            st = self.data.statustypes[status.type]
            self.pgc.addstr(x, 22, st.desc, st.fg, colours.BLACK)
            x += len(st.desc) + 1
        #self.pgc.addstr(0, 23, " " * 12, colours.LIGHTGREY, colours.BLACK)
        if state.damage_indicator:
            for m in state.current_level.mobs:
                if m.id == state.damage_indicator:
                    hpfrac = min(10, m.hp * 10 / m.maxhp)
                    self.pgc.addstr(0, 23, "[", colours.WHITE, colours.BLACK)
                    self.pgc.addstr(1, 23, "%s%s" % ("*" * hpfrac, "-" * (10-hpfrac)), utils.fract_colour(m.hp, m.maxhp), colours.BLACK)
                    self.pgc.addstr(11, 23, "]", colours.WHITE, colours.BLACK)
                    #self.pgc.addstr(13, 23, self.data.mobtypes[m.type].name, colours.LIGHTGREY, colours.BLACK)
        


    def message_history(self, messages):
        self.clear()
        y = 2
        self.pgc.addstr(0,0, "Message History", 7, 0)
        for message in messages:
            if y+1 >= self.pgc.rows:
                self.pgc.addstr(0, self.pgc.rows-1, "[Press any key for more]", 7, 0)
                self.pgc.refresh()
                self.pgc.getch()
                self.clear()
                y = 0
            self.pgc.addstr(0, y, message, 7, 0)
            y += 1
        self.pgc.addstr(0, self.pgc.rows-1, "[Press any key to continue]", 7, 0)
        self.pgc.refresh()
        self.pgc.getch()

    def render_text_file(self, f):
        self.clear()
        y = 0
        for line in open(f):
            line = line.rstrip()
            if y+1 >= self.pgc.rows:
                self.pgc.addstr(0, self.pgc.rows-1, "[Press any key for more]", 7, 0)
                self.pgc.refresh()
                self.pgc.getch()
                self.clear()
                y = 0
            self.pgc.addstr(0, y, line, 7, 0)
            y += 1
        self.pgc.addstr(0, self.pgc.rows-1, "[Press any key to continue]", 7, 0)
        self.pgc.refresh()
        self.pgc.getch()

    def ask_for_number(self, message, fg, bg, minval, maxval, default):
        message = "%s (%s-%s)" % (message, minval, maxval)
        self.render_message(message)
        n = self.input_number(len(message)+1, 0, fg, bg, minval, maxval, default)
        self.render_message(None)
        return n

    def input_number(self, x, y, fg, bg, minval, maxval, default):
        str = "%s" % default
        l = len("%s" % maxval)
        for i in range(l):
            self.pgc.addch(x+i, y, " ", fg, bg)
        self.pgc.addstr(x, y, str, fg, bg)
        self.pgc.refresh()
        changed = False
        while 1:
            ch = self.pgc.getch()
            if ch == "RETURN" and len(str) > 0:
                v = int(str)
                if v >= minval and v <= maxval:
                    return v
            elif ch == "BACKSPACE":
                if not changed:
                    str = ""
                    changed = True
                elif str:
                    str = str[:-1]
            elif ch in "0123456789":
                if not changed:
                    changed = True
                    str = ""
                if len(str) < l:
                    str += ch

            for i in range(l):
                self.pgc.addch(x+i, y, " ", fg, bg)
            self.pgc.addstr(x, y, str, fg, bg)
            self.pgc.refresh()
                
    def ask_for_string(self, message):
        message = "%s " % message
        self.render_message(message)
        n = self.input_string(len(message) + 1, 0, 7, 0, 80 - len(message)+1)
        self.render_message(None)
        return n

    def input_string(self, x, y, fg, bg, l):
        str = ""
        for i in range(l):
            self.pgc.addch(x+i, y, " ", fg, bg)
        self.pgc.addstr(x, y, str, fg, bg)
        self.pgc.refresh()
        while 1:
            ch = self.pgc.getch()
            if ch == "RETURN":
                return str
            elif ch == "BACKSPACE":
                str = str[:-1]
            elif len(ch) == 1:
                if len(str) < l:
                    str += ch

            for i in range(l):
                self.pgc.addch(x+i, y, " ", fg, bg)
            self.pgc.addstr(x, y, str, fg, bg)
            self.pgc.refresh()

    def select_class(self, data):
        for x in range(80):
            for y in range(25):
                self.pgc.addch(x, y, " ", 7, 0)

        l = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

        self.pgc.addstr(0, 0, "Select a class:", 7, 0)

        for i in range(len(data.mobtypes)):
            ch = l[i]
            mtype = self.data.mobtypes[i]
            if not mtype.ch == "@":
                continue
            name = mtype.name
            color = mtype.fg
            s = "%s) %s" % (ch, name)
            self.pgc.addstr((i/18) * 40, (i % 18)+2, s, color, 0)

        self.pgc.refresh()
        c = -1
        while c == -1:
            ch = self.pgc.getch()
            self.pgc.refresh()
            if len(ch) == 1 and ch in l:
                chi = l.index(ch)
                if chi < len(data.mobtypes) and data.mobtypes[chi].ch == "@":
                    c = chi

        for x in range(80):
            for y in range(25):
                self.pgc.addch(x, y, " ", 7, 0)

        return c
